//pragma javascript
//pragma module NMonster

var debugMode = false;
function debugLog(msg) {
	if (!debugMode) return;
	console.log('Debug: '+msg);
}
// 集中的延时任务调度
var TaskExecList = {};
/*
{timestamp: { func: function(){},args: [] }}
*/
function __NMonsterExecTaskList() {
	const nowtimestamp = new Date().getTime();
	for (let i in TaskExecList) {
		if (nowtimestamp < i) continue;
		let obj = TaskExecList[i];
		try {
			obj["func"].apply(this, obj["args"]);
			delete TaskExecList[i];
		} catch(err) {
			logger.info("§4NMonster 的延时任务出现了错误, tag: "+(obj && obj["tag"])+"，timestamp: "+i);
			logger.info(err);
			delete TaskExecList[i];
		}
	}
}
manager.createLoopTask("__NMonsterExecTaskList", 1);
function addTimeoutTask(timestamp, obj) {
	while (TaskExecList[timestamp]) {
		timestamp ++;
	}
	TaskExecList[timestamp] = obj;
	return timestamp;
}

// 为怪物属性申请共享内存地址
if (!database.memoryStorage.getItem("MonsterAttr")) {
	database.memoryStorage.setItem("MonsterAttr", {});
}
// 获取玩家属性，id为实体唯一ID、mode为数据模式 模式为1时返回原始数据否则返回随机后的值
export function GetMonsterAttr(id, mode, key) {
	let data = database.memoryStorage.getItem("MonsterAttr")[id];
	if (!data) {
		return {};
	}
	data = JSON.parse(JSON.stringify(data));
	if (mode) {
		return data;
	}
	if (key) {
		if (!data.Main[key]) {
			return 0;
		}
		if (typeof(data.Main[key]) === "object") {
			return getRandomRange(data.Main[key][0], data.Main[key][1]);
		}
		return data.Main[key];
	}
	for (let i in data.Main) {
		if (data.Main[i][0] === data.Main[i][1]) {
			data.Main[i] = data.Main[i][0];
		} else {
			data.Main[i] = getRandomRange(data.Main[i][0], data.Main[i][1]);
		}
	}
	return data.Main;
}
export function SetMonsterAttr(id, item, newAttr) {
	if (typeof(newAttr) === "string") newAttr = JSON.parse(newAttr);
	let data = database.memoryStorage.getItem("MonsterAttr");
	if (!data[id]) {
		data[id] = {Main: {}};
	}
	if ("Main" === item) {
		logger.warning("setMonsterAttr(): '"+item+"' is the wrong item parameter.");
		return false;
	}
	if (!data[id][item]) data[id][item] = {};
	let oldAttr = data[id][item];
	for (let i in newAttr) {
		if (typeof(newAttr[i]) === 'string' || typeof(newAttr[i]) === 'number') {
			newAttr[i] = [Number(newAttr[i]), Number(newAttr[i])];
		}
		if (typeof(newAttr[i]) === 'object') {
			if (!data[id].Main[i]) data[id].Main[i] = [0, 0];
			for (let k = 0; k<newAttr[i].length; k++) {
				data[id].Main[i][k] = data[id].Main[i][k] - (oldAttr[i] ? oldAttr[i][k] : 0) + newAttr[i][k];
			}
			continue;
		}
	}
	for (let i in oldAttr) {// 处理oldAttr有但是newAttr没有的属性
		if (!newAttr[i]) if (typeof(oldAttr[i]) === 'object') {
			if (!data[id].Main[i]) data[id].Main[i] = [0, 0];
			for (let k = 0; k<oldAttr[i].length; k++) {
				data[id].Main[i][k] = data[id].Main[i][k] - oldAttr[i][k];
			}
		} else {
			data[id].Main[i] = data[id].Main[i] - oldAttr[i];
		}
	}
	data[id][item] = newAttr;
	database.memoryStorage.setItem("MonsterAttr", data);
	return true;
}

var File = Java.type('java.io.File'), FileOutputStream = Java.type('java.io.FileOutputStream'), FileInputStream = Java.type('java.io.FileInputStream'), Base64 = Java.type('java.util.Base64');

// 创建刷怪点配置文件
manager.createConfig(manager.getFile("NMonster", "刷怪点.yml"), 2);
if (manager.readFile('./plugins/BlocklyNukkit/NMonster/Config.yml') === "FILE NOT FOUND") {
	manager.createConfig(manager.getFile("NMonster", "Config.yml"), 2);
	manager.writeFile("./plugins/BlocklyNukkit/NMonster/Config.yml", manager.JSONtoYAML(JSON.stringify(
		{language:'chs', version:version, MaxExecNum: 3, playerlist: {
			PlayerMode: [2, 0]
		}}
	)));
}
manager.createConfig(manager.getFile("NMonster", "NBT掉落物.json"), 2);
function isExistDir(path) {
	const dir = new File(path);
	if (!dir.exists()) {// 判断目录是否存在
		dir.mkdir();
	}
}
function b64tofile(b64str, outdir) {
	var b = Base64.getDecoder().decode(b64str), out = new FileOutputStream(outdir);
	for (var i = 0; i < b.length; ++i) {
		if (b[i] < 0) b[i] += 256;
	}
	out.write(b);
	out.flush();
	out.close();
	return true;
}
const b64skin = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAV1BMVEUAAAD//fv///D++fj99fT+9PL99PT88vD+8O787Oj56+n84OH/47/y4+D/2eT6ztDmztD6x7a01s//q6iuwtbrlLHrk7G1m8SxjpGjepWRao2FbW55XmFhKOxcAAAAAXRSTlMAQObYZgAAAoRJREFUeNrtlttyozAMhn0gddEuTmtZpdvy/s+544N8AJIhdPZiZ/JPBiFif5ZlgyxEFhRN8SdWmqZ63RUYM2hjfgDg8bPEowIzaD0YgNfL5XJ5hROAqACQ8hSAp5AAZ6aQkngecCQCvNPxlup6TABYF7UsKxgwBkztwX62BQCTQYIKgPQwAoYVYMiAYFNDkYGEmGmTCdZMAgYwGgaAaxQUn63JgCEAMW9RAzAEO4AAHRpqgGW5XpcFip9tSZUWRgtd9/iQL2AmM0wGls/v6/X7c2GfrW5fhWq1TgAdASYAXt6kfHtZ2Gd7E5Ct4LeP15/9zVs5lQt35YsQiIhERGW/eOxUnisr5bi3wdYAvAFAdRhAtAtw+wCFbgWgcaQ9AG0BiKgCoFcD6PJB5JS1CjtAeMIAm4wqU/B+9g5VvHfOUSAo1wJsiMChc6GB9TZGVImIob9VCWAdkSNCXCUwpTDQOYLVlJJvrbexWQcYg2rTfOsQbejkbDI8wzSObQEy6VeUlDIPgWk06+OkHFITqfX2DuAr6E/UV3ufAvOeyLm9COJMRinle9DvqPf2Po7t59mHVNEdwK0I0uxDBO2WCwDVA+p+cGn185pSpzsRpP45dc0a9s0aQAf++MjZtuu9fRvw1FNPPaa2xCBu/hKIeBaAfMGzEfyL+fq+WhPiYx+Rdbn/zwD9p9Qjl7pU2Q4AfHuo8HMqJGjtYUA+VOQi7bmcxkJxCBBKn/P1SJPPDbFQKDqeg5HPDarkIBxcDgC4zHPZJyLFR6RDEWwB8Vh2fBW4yHLR9SECl1PhTwBmTy73Jz+vNkvxRPUqQKUIXFO9/R4A22/CNoLOH3cj2OyD7rywC2j0F+DPXhic88ufAAAAAElFTkSuQmCC'

const CommandList = [
	['副本', '年系列副本插件'],
	['副本 set', '设置刷怪点 UI'],
	['副本 reload', '重载配置文件'],
	['副本 add <怪物名> [刷怪点代号]', '添加刷怪点'],
	['副本 remove <刷怪点代号>', '删除刷怪点'],
	['副本 save [标识名]', '保存NBT物品'],
	['副本 delete [标识名]', '删除NBT物品'],
	['副本 gen <怪物名> <世界名> <x> <y> <z>', '生成指定怪物到指定位置'],
	['副本 censor [刷怪点名]', '检查刷怪点并重新生成']
];
var Config = {},
	MonsterConfig = {},// 配置文件 - 怪物数据
	SkillConfig = {},// 配置文件 - 技能
	MonsterRefreshList = {},// 配置文件 - 刷怪点
	NBTItemData = {},// 配置文件 - NBT掉落物
	MonsterObj = {},// 存在的怪物的交互数据
	ExistMonsterList = {},// 存在的怪物刷怪点对照
	RefreshTaskID = {},// 已死亡怪物刷新点任务的ID
	MonsterSendOfProjectile = {};// 弹射物与怪物实体的对照
/* 
ExistMonsterList[id] = [data.刷新CD, RefreshName];
RefreshTaskID[RefreshName] = timestamp;
MonsterSendOfProjectile[projectileID] = monsterID;
*/
const ExecutorCommandSender = Java.type('cn.nukkit.command.ExecutorCommandSender');// 用于执行命令时生成执行者
var RSHealthAPI = manager.getPlugin("HealthAPI") ? Java.type("healthapi.PlayerHealth") : false;// 获取血量核心插件
var NWeapon = false;
var MagicItem = manager.getPlugin("MagicItem") ? Java.type('cn.ankele.plugin.MagicItem') : false;// 获取魔法物品插件
addTimeoutTask(new Date().getTime()+1000, {
	func: function (){
		NWeapon = require("NWeapon") || false;// 获取NWeapon插件
	},
	args: []
})

const version = '2022-02-09';
manager.bStats("NMonster", version, "Mcayear", 14239);// 插件状态接口 - bStats
manager.createCommand(CommandList[0][0], CommandList[0][1], 'NMonsterFuncCore');
// 创建目录
isExistDir("./plugins/BlocklyNukkit/NMonster/怪物/");
isExistDir("./plugins/BlocklyNukkit/NMonster/技能/");
manager.concurrentRun("loadConfig");
function NMonsterFuncCore(sender, args) {
	if (args.length === 0) {
		let helpStr = ['§7------ NMonster Help ------§a'];
		for (let i = 0; i < CommandList.length; i++) {
			helpStr.push("§2/" + CommandList[i][0] + ":§f " + CommandList[i][1]);
		}
		return sender.sendMessage(helpStr.join("\n"));
	}
	if (!sender.isOp()) {
		return sender.sendMessage("[NMonster] only op.");
	}
	switch (args[0]) {
		case 'debug': {
			if (debugMode) {
				debugMode = false;
				console.warn("debug已关闭");
			} else {
				debugMode = true;
				console.warn("debug已开启");
			}
			break;
		}
		case 'help': {
			let helpStr = ['§7------ NMonster Help ------§a'];
			for (let i = 0; i < CommandList.length; i++) {
				helpStr.push("§2/" + CommandList[i][0] + ":§f " + CommandList[i][1]);
			}
			sender.sendMessage(helpStr.join("\n"));
			break;
		}
		case 'reload': {
			for (let i in RefreshTimeList) {
				if (RefreshTimeList[i].e) {
					entity.removeEntity(RefreshTimeList[i].e);
				}
				delete RefreshTimeList[i];
			}
			for (let id in ExistMonsterList) {
				const data = MonsterRefreshList[ExistMonsterList[id][1]];
				if (!data) {
					continue;
				}
				let npc = entity.getEntityByLevelAndID(server.getLevelByName(data[4]), id);
				let xid = id;
				if (BossBarMap.has(xid)) {
					BossBarMap.get(xid).forEach(p => {
						if (p.isOnline()) {
							let pData = BossBarPlayerMap.get(p.name);
							let pDataBossBar = pData[xid];
							if (pDataBossBar) {
								p.removeBossBar(pDataBossBar.BossBarId);
							}
						}
						BossBarPlayerMap.delete(p.name);
					})
					BossBarMap.delete(xid);
				}
				if (npc) {
					npc.close();
				}
			}
			for (let i in RefreshTaskID) {
				delete TaskExecList[RefreshTaskID[i]];
			}
			RefreshTimeList = {};
			ExistMonsterList = {};
			RefreshTaskID = {};
			loadConfig();
			sender.sendMessage("[NMonster] 重载成功");
			break;
		}
		case 'set':
			sender.sendMessage("[NMonster] 功能未完善");
			break;
		case 'add': {
			if (args.length < 2) {
				return sender.sendMessage("[NMonster] 命令参数不足");
			}
			if (!MonsterConfig[args[1]]) {
				return sender.sendMessage("[NMonster] 不存在 " + args[1] + " 怪物的配置文件");
			}
			let pointName = args[1] + String(Math.random()).substr(3, 4);
			if (args.length > 2) {
				if (MonsterRefreshList[args[2]]) {
					sender.sendMessage("[NMonster] 刷怪点代号 " + args[2] + " 已存在,正在尝试随机代号..");
				} else {
					pointName = args[2];
				}
			} else {
				sender.sendMessage("[NMonster] 生成刷怪点随机代号..");
			}
			if (MonsterRefreshList[pointName]) {
				return sender.sendMessage("[NMonster] 刷怪点代号 " + pointName + " 已存在,已取消本次刷怪点设置");
			}
			MonsterRefreshList[pointName] = [args[1], sender.x, sender.y, sender.z, sender.getLevel().getName(), sender.yaw, sender.pitch];
			sender.sendMessage("[NMonster] 添加成功, 使用 §c/副本 remove " + pointName + "§r 可移除该刷怪点.");
			GenMonster(pointName, MonsterConfig[args[1]], MonsterRefreshList[pointName], true);
			manager.writeFile('./plugins/BlocklyNukkit/NMonster/刷怪点.yml', manager.JSONtoYAML(JSON.stringify(MonsterRefreshList)));
			break;
		}
		case 'remove':
			if (args.length < 2) return sender.sendMessage("[NMonster] 命令参数不足");
			if (MonsterRefreshList[args[1]]) {
				sender.sendMessage("[NMonster] 成功移除刷怪点 §7" + args[1]);
				delete MonsterRefreshList[args[1]];
				manager.writeFile('./plugins/BlocklyNukkit/NMonster/刷怪点.yml', manager.JSONtoYAML(JSON.stringify(MonsterRefreshList)));
			} else {
				sender.sendMessage("[NMonster] 刷怪点 §7" + args[1] + " §r不存在");
			}
			break;
		case 'save': {
			let Item = blockitem.getItemInHand(sender.getPlayer());
			const keyName = args.length === 1 ? (Math.random()+[]).substr(2, 6) : args[1];
			NBTItemData[keyName] = [Item.getId(), Item.getDamage(), blockitem.getNBTString(Item)];
			sender.sendMessage("[NMonster] >>已保存nbt物品: "+keyName);
			manager.writeFile("./plugins/BlocklyNukkit/NMonster/NBT掉落物.json", JSON.stringify(NBTItemData));
			break;
			}
		case 'delete':
			if (!NBTItemData[args[1]]) sender.sendMessage("[NMonster] >>删除失败，不存在nbt物品: "+args[1]);
			delete NBTItemData[args[1]];
			sender.sendMessage("[NMonster] >>已删除nbt物品: "+args[1]);
			manager.writeFile("./plugins/BlocklyNukkit/NMonster/NBT掉落物.json", JSON.stringify(NBTItemData));
			break;
		case 'gen': {}
		case 'censor': {
			let RefreshData = MonsterRefreshList[args[1]];
			if (!RefreshData) return logger.warning("刷怪点错误, 刷新点 " + args[1] + " 不存在.");
			if (!MonsterConfig[RefreshData[0]]) return logger.warning("刷怪点错误, 怪物 " + RefreshData[0] + " 配置文件不存在.");
			let status = 0;// 0 = 未知, 1 = 存活, 2 = 等待刷新
			let entityID = null;
			for (let id in ExistMonsterList) {
				if (ExistMonsterList[id][1] === args[1]) {
					logger.info("怪物检查，"+args[1]+" 存活！");
					sender.sendMessage("怪物检查，"+args[1]+" 存活！");
					status = 1;
					entityID = id;
					break;
				}
			}
			if (RefreshTaskID[args[1]]) {
				logger.info("怪物检查，"+args[1]+" 等待刷新！"+Date2YMD(RefreshTaskID[args[1]]));
				sender.sendMessage("怪物检查，"+args[1]+" 等待刷新！"+Date2YMD(RefreshTaskID[args[1]]));
				status = 2;
			}
			switch (status) {
				case 0: {
					logger.info("怪物检查，"+args[1]+" 异常，两个列表中均为存在！");
					sender.sendMessage("怪物检查，"+args[1]+" 异常，两个列表中均为存在！");
					break;
				}
				case 1: {
					const d = MonsterRefreshList[ExistMonsterList[entityID][1]];
					if (!d) {
						logger.warning("怪物检查，刷怪点错误刷新点 " + args[1] + " 不存在");
						break;
					}
					let npc = entity.getEntityByLevelAndID(server.getLevelByName(d[4]), entityID);
					if (npc) {
						if (isPlayer(sender)) particle.drawDot(npc.getPosition(), 18, 0, 255, 0, sender);
						sender.sendMessage("实体位置："+getStringPos(npc));
						const npc_obj_str = JSON.stringify(MonsterObj[entityID]);
						logger.info(npc_obj_str);
						sender.sendMessage(npc_obj_str);
					} else {
						sender.sendMessage("怪物检查，"+args[1]+" 异常，未能获取实体！");
					}
					break;
				}
				case 2: {
					
				}
			}
			break;
			}
		default:
			sender.sendMessage("[NMonster] Unknow args 1:" + args[0]);
	}
}
/**
 * 获取路径下文件数量
 * @param path {String} 路径
 * @returns {array} 文件列表的数组
 */
function getFileList(path) {
	return new File(path).listFiles();
}
const EntityArmorInventory = Java.type("cn.nukkit.inventory.EntityArmorInventory");
const EntityEquipmentInventory = Java.type("cn.nukkit.inventory.EntityEquipmentInventory");
/**
 * 生成怪物
 * @param RefreshName {String} 刷怪点名
 * @param data {object} 怪物的配置数据
 * @param position {array} 怪物生成点位置
 * @param isSpawn {object} 是重生成
 * @param [worldList] {array} 世界列表
 */
function GenMonster(RefreshName, data, position, isSpawn, worldList) {
	if (isSpawn && data.重生执行命令) {
		for (let i = 0; i < data.重生执行命令.length; i++) {
			if (data.重生执行命令[i][0] >= getRandom(4)) {
				for (let j = 1; j < data.重生执行命令[i].length; j++) {
					server.dispatchCommand(server.getConsoleSender(), data.重生执行命令[i][j]
					.replace("{mob.name}", position[0])
					.replace("{mob.x}", position[1].toFixed(0))
					.replace("{mob.y}", position[2].toFixed(0))
					.replace("{mob.z}", position[3].toFixed(0))
					.replace("{mob.world}", position[4]));
				}
			}
		}
	}
	if (worldList && worldList.indexOf(position[4]) === -1) {
		return logger.warning("刷怪点配置有误，不存在世界 "+position[4]);
	}
	world.loadLevel(position[4]);
	const refreshName = position[0];
	let npcpos = getPosition(position.slice(1, 5)), npc;

	if (isNaN(data.皮肤)) {
		if (!(new File('./plugins/BlocklyNukkit/skin/' + data.皮肤 + '.png').exists())) {
			logger.warning('皮肤 "' + data.皮肤 + '" 不存在, 已使用默认皮肤替代');
			b64tofile(b64skin, './plugins/BlocklyNukkit/skin/' + data.皮肤 + '.png');
		}
		npc = entity.buildNPC(npcpos, data.名字, data.皮肤, 1, "NPCTickCallback", "NPCAttackCallback");
		if (data.装备栏) {
			if (data.装备栏[0]) inventory.setEntityItemHelmet(npc, blockitem.buildItem(data.装备栏[0], 0, 1));
			if (data.装备栏[1]) inventory.setEntityItemChestplate(npc, blockitem.buildItem(data.装备栏[1], 0, 1));
			if (data.装备栏[2]) inventory.setEntityItemLeggings(npc, blockitem.buildItem(data.装备栏[2], 0, 1));
			if (data.装备栏[3]) inventory.setEntityItemBoots(npc, blockitem.buildItem(data.装备栏[3], 0, 1));
			if (data.装备栏[4]) inventory.setEntityItemInHand(npc, blockitem.buildItem(data.装备栏[4], 0, 1));
			if (data.装备栏[5]) inventory.setEntityItemInOffHand(npc, blockitem.buildItem(data.装备栏[5], 0, 1));
		}
		if (data.boxSize) {
			npc.setWidth(data.boxSize[0]);
			npc.setHeight(data.boxSize[1]);
		}
	} else {
		npc = entity.buildVanillaNPC(npcpos, data.名字, data.皮肤, 1, "NPCTickCallback", "NPCAttackCallback");
		const boxSize = getEntityBox(data.皮肤);// 获取碰撞箱的高宽
		if (boxSize.length > 0) {
			npc.setWidth(boxSize[0]);
			npc.setHeight(boxSize[1]);
		}
		if (data.装备栏) {
			/*
			if (data.装备栏[0]) armorInv.setHelmet(blockitem.buildItem(302, 0, 1));
			if (data.装备栏[1]) armorInv.setChestplate(blockitem.buildItem(data.装备栏[1], 0, 1));
			if (data.装备栏[2]) armorInv.setLeggings(blockitem.buildItem(data.装备栏[2], 0, 1));
			if (data.装备栏[3]) armorInv.setBoots(blockitem.buildItem(data.装备栏[3], 0, 1));
			if (data.装备栏[4]) npc.equipmentInventory.setItemInHand(blockitem.buildItem(data.装备栏[4], 0, 1));
			if (data.装备栏[5]) npc.equipmentInventory.setItemInOffhand(blockitem.buildItem(data.装备栏[5], 0, 1));
			*/
		}
	}
	npc.yaw = position[5];
	// npc.pitch = position[6];
	npc.setEnableAttack(true);
	if (data.弹跳力) {
		npc.setJumpHigh(data.弹跳力);
	}
	npc.setSpeed(data.移动速度);
	npc.setEnableGravity(true);
	npc.setG(1.7);
	npc.setScale(data.大小);

	npc.setEnableKnockBack(false);
	// npc.setKnockBase(1.5);

	const id = entity.getEntityID(npc);
	MonsterObj[id] = {
		refreshName: refreshName, // 刷新点名字
		second: 0, // 时间
		callTick: 0, // 时间

		//strollTick: 120, // 随机移动的间隔 5-20s
		//eludeTick: -1, // 被攻击时躲避行为的持续时间 3-7s

		AttackCooldown: {}, // 用来处理玩家的攻击冷却
		attackTick: data.攻击间隔, // 怪物的攻击间隔
		underAttack: 1, // 受到玩家攻击
		skill: {
			时刻技能: [],
			打击技能: [],
			反击技能: [],
			血量技能: []
		},
		backspawn: -1, // 返回重生点
		notfighting: 0, // 非战斗状态判断
		target: false, // 怪物的目标
		info: {
			xname: position[0], // 刷怪点名字
			name: data.名字.split("\n")[0],// 名字
			showname: data.名字.split("\n").slice(1).join("\n"),// 非名字
			pos: npcpos,
			maxhealth: null// number
		},
		atkList: {}, // 攻击怪物的玩家列表
		lateAtker: {} // 最后攻击怪物的玩家
	}
	if (data.属性) {
		SetMonsterAttr(id, "NMonster", data.属性);
	}
	let attr = GetMonsterAttr(id);
	const health = attr.血量值 * (1 + (attr.生命加成 || 0));

	MonsterObj[id].info.maxhealth = health;

	if (typeof(data.皮肤) === "number") {
		MonsterObj[id].info.name = data.名字;
		delete MonsterObj[id].info["showname"];
	}
	if (data.巡回路径) {
		MonsterObj[id].tour = {path: data.巡回路径, mode: (data.巡回模式 || 1), current: []};
		delete MonsterObj[id]["strollTick"];
	}
	if (data.无目地移动) {
		MonsterObj[id]["strollTick"] = getRandomRange(5, 20) * 20;
	}
	if (data.躲避行为) {
		MonsterObj[id]["eludeTick"] = -1;
	}
	entity.setEntityMaxHealth(npc, health);
	entity.setEntityHealth(npc, health);
	ResetMonsterSkill(id, data);
	if (RefreshName.length === 0) {// 如果没有 刷怪点名 则不再刷新
		ExistMonsterList[id] = [data.刷新CD];
	} else {
		ExistMonsterList[id] = [data.刷新CD, RefreshName];
	}
	setNPCEntityScoreTag(id, npc, MonsterObj[id]);// 怪物名字下方的其他显示信息
	npc.start();
}
/**
 * 重新设置(初始化)生物技能的临时数据
 * @param id {String} 生物唯一ID
 * @param data {object} 怪物的配置数据
 */
function ResetMonsterSkill(id, data) {
	if (data.时刻技能) {
		MonsterObj[id].skill.时刻技能 = [];
		for (var i = 0; i<data.时刻技能.length; i++) {
			MonsterObj[id].skill.时刻技能[i] = data.时刻技能[i].split(":")[0];
		}
	}
	if (data.打击技能) {
		MonsterObj[id].skill.打击技能 = [];
		for (var i = 0; i<data.打击技能.length; i++) {
			MonsterObj[id].skill.打击技能[i] = data.打击技能[i].split(":")[0];
		}
	}
	if (data.反击技能) {
		MonsterObj[id].skill.反击技能 = [];
		for (var i = 0; i<data.反击技能.length; i++) {
			MonsterObj[id].skill.反击技能[i] = data.反击技能[i].split(":")[0];
		}
	}
	if (data.血量技能) {
		MonsterObj[id].skill.血量技能 = [];
		for (var i = 0; i<data.血量技能.length; i++) {
			MonsterObj[id].skill.血量技能[i] = data.血量技能[i];
		}
	}
}
function NPCAttackCallback(ent, event) {// NPC被攻击时回调
	const id = entity.getEntityID(ent);
	if (MonsterObj[id] === undefined) return;
	const cause = event.getCause().toString();
	var player = {isIt: true, name: cause};
	var data = MonsterConfig[MonsterObj[id].info.xname];
	const time = new Date().getTime();
	// 攻击实体判断
	if (cause === "ENTITY_ATTACK") {
		player = event.getDamager();
	} else if (cause === "PROJECTILE") {
		player = event.getDamager();
	}
	if (!player.isIt) {
		MonsterObj[id].lateAtker = player;
		for (var i = 0; i < MonsterObj[id].skill.反击技能.length; i++) {
			if (MonsterObj[id].skill.反击技能[i] < 1) {// 重置并执行反击技能
				const arr = data.反击技能[i].split(":");
				MonsterObj[id].skill.反击技能[i] = arr[0];
				ExecSkill(arr[1], ent);
			} else {
				MonsterObj[id].skill.反击技能[i] --;
			}
		}
		if (data.受击粒子方块ID) {
			const arr = data.受击粒子方块ID.split(":");
			particle.drawBlockBreak(ent, blockitem.buildBlock(arr[0], arr[1]));
		}
	}
	ent.stopMove();
	addTimeoutTask(new Date().getTime() + 50, {
		tag: "受到伤害->检查血量",
		func: MonsterHealthCheck,
		args: [entity.getEntityHealth(ent), ent, player]
	});
}
function MonsterHealthCheck(beforeHealth, ent, player, isKill) {
	const id = entity.getEntityID(ent);
	var Damage = beforeHealth - entity.getEntityHealth(ent);
	if (isKill) {
		Damage = ent.getHealth();
	} else if (Damage === 0 || MonsterObj[id] === undefined) {
		return;
	}
	var data = MonsterConfig[MonsterObj[id].info.xname];
	if (!player.isIt) {
		if (MonsterObj[id].atkList[player.name] === undefined) {
			MonsterObj[id].atkList[player.name] = 0;
		}
		MonsterObj[id].atkList[player.name] += Damage;
		if (data.主动攻击 == false && !MonsterObj[id].target) {
			MonsterObj[id].target = player;
		}
	}
	for (var i = 0; i < data.血量技能.length; i++) {
		if (!MonsterObj[id].skill.血量技能[i]) continue;
		const arr = data.血量技能[i].split(":");
		if (eval(entity.getEntityHealth(ent)+arr[0])) {
			MonsterObj[id].skill.血量技能[i] = false;
			ExecSkill(arr[1], ent);
		}
	}
	if (!ent.isAlive() || ent.getHealth() < 1 || isKill) {// 怪物被击败
		if (player.isIt) player = MonsterObj[id].lateAtker;
		if (data.排行榜) {
			let str = "§7+++ §f玩家排名 §7+++";
			let arr = [];
			for (let i in MonsterObj[id].atkList) {
				arr.push({name: i, value: MonsterObj[id].atkList[i]});
			}
			arr.sort(compare("value"));
			let playerlist = [];
			for (var i = 0; i<arr.length; i++) {
				let p = server.getPlayer(arr[i].name);
				playerlist.push(p);
				if (i < 4) {
					str += "\n§a第"+(i+1)+"名 §c[§eLv."+(p ? entity.getPlayerExpLevel(p) : "-1")+"§c]§r"+arr[i].name+"("+arr[i].value+")";
				}
			}
			for (var i = 0; i<playerlist.length; i++) {
				if (playerlist[i] === null || playerlist[i].isOnline() === false) {
					continue;
				}
				playerlist[i].sendMessage(str + "\n§a我在第"+(i+1)+"名");
				if (data.排行榜奖励 && data.排行榜奖励[i]) {
					data.排行榜奖励[i].forEach(function(v) {
						let arr = v.split(":");
						if (arr.length > 1) {
							if (arr[arr.length-1] < getRandom(4)){
								return;
							}
							arr.length = arr.length-1;
						}
						server.dispatchCommand(server.getConsoleSender(), arr.join(":").replace("{player}", player.name)
							.replace("{killer}", player.name)
							.replace("{mob.name}", MonsterObj[id].info.xname));
					});
				}
			}
		}
		if (data.死亡音效) {
			ent.getPlayersIn(6).forEach(p => {
				entity.makeSoundToPlayer(p, data.死亡音效);
			});
		}
		var execNum = 0;
		if (data.死亡执行命令) for (var i = 0; i < data.死亡执行命令.length; i++) {
			let arr = String(data.死亡执行命令[i][0]).split("/");
			let Probability = arr[0];
			let DropTag = arr[1];// 掉落物标签，用于统计掉落数
			arr = null;
			if (Probability >= getRandom(4)) {
				if (Probability < 9500) {
					if (execNum == (Config.MaxExecNum || 3)) break;
					execNum ++;
				}
				for (var j = 1; j < data.死亡执行命令[i].length; j++) server.dispatchCommand(server.getConsoleSender(), data.死亡执行命令[i][j]
				  .replace("{killer}", player.name)
				  .replace("{mob.name}", MonsterObj[id].info.xname)
				  .replace("{mob.x}", ent.getLevel().x)
				  .replace("{mob.y}", ent.getLevel().y)
				  .replace("{mob.z}", ent.getLevel().z)
				  .replace("{mob.world}", ent.getLevel().name));
			}
		}
		if (data.复活倒计时 && ExistMonsterList[id].length === 2) {
			RefreshTimeList[ExistMonsterList[id][1]] = {t: ExistMonsterList[id][0]};
		}
		
		if (isPlayer(player)) {
			const popupMsg = [];
			if (data.掉落经验) {
				let exp = data.掉落经验[0];
				if (data.掉落经验.length === 2) {
					exp = getRandomRange.apply(this, data.掉落经验);
				}
				let addexp = 0;
				if (NWeapon) {
					let value = NWeapon.GetPlayerAttr(player.name, false, "经验加成");
					if (value) {
						addexp = Math.round(value * exp);
						player.addExperience(addexp);
					}
				}
				//blockitem.makeExpBall(ent, exp);
				player.addExperience(exp);
				popupMsg.push("获得了 "+(exp+addexp)+" 点经验");
			}
			if (data.掉落金币) {
				let money = data.掉落金币[0];
				if (data.掉落金币.length === 2) {
					money = getRandomRange.apply(this, data.掉落金币);
				}
				manager.addMoney(player, money);
				popupMsg.push("获得了 "+money);
			}
			if (popupMsg.length > 0) player.sendPopup(popupMsg.join('\n'));

			for (let i = 0; i<data.掉落物.length; i++){
				const str = data.掉落物[i];
				const arr = str.split("@");
				if (arr[0] === "mi") {
					if (MagicItem) {
						const items = MagicItem.getItemsMap();
						const otherItems = MagicItem.getOthers();
						const args = arr[1].split(":");

						const tailPart = String(args[args.length-1]).split("/");// "mi@Num:ItemName:Probability/DropTag"
						const Probability = tailPart[0];
						const DropTag = tailPart[1];// 掉落物标签，用于统计掉落数
						if (Probability < getRandom(4)) {
							continue;
						}
						let item;
						if (items.containsKey(args[1])) {
							item = items.get(args[1]);
							item.setCount(args[0]);
						} else if (otherItems.containsKey(args[1])) {
							item = otherItems.get(args[1]);
							item.setCount(args[0]);
						} else {
							logger.info("MagicItem物品不存在："+args[1]);
							continue;
						}
						blockitem.makeDropItem(ent, item);
					} else {
						logger.warning("你没有使用 MagicItem 插件却在试图获取它的物品："+str);
					}
				} else if (arr[0] === "nbt") {
					const args = arr[1].split(":");
					const tailPart = String(args[args.length-1]).split("/");// "nbt@ID:Damage:Num:ItemName:Probability/DropTag"
					const Probability = tailPart[0];
					const DropTag = tailPart[1];// 掉落物标签，用于统计掉落数
					if (Probability < getRandom(4)) {
						continue;
					}
					let item = false;
					if (args.length === 3) {
						let NBTData = NBTItemData[args[1]];
						if (NBTData) {
							item = blockitem.buildItem(NBTData[0], NBTData[1], args[0]);
							if (NBTData[2]) blockitem.putinNBTString(item, NBTData[2]);
						} else {
							logger.warning("NBT物品不存在: "+args[1]);
						}
					} else if (args.length === 5) {
						item = blockitem.buildItem(args[0], args[1], args[2]);
						if (NBTItemData[args[3]]) {
							if (NBTItemData[args[3]][2]) blockitem.putinNBTString(item, NBTItemData[args[3]][2]);
						} else {
							logger.warning("NBT物品不存在: "+args[3]);
						}
					} else {
						logger.warning("怪物配置文件 - 掉落物 - 配置有误");
					}
					if (item != false) blockitem.makeDropItem(ent, item);
				} else if (arr[0] === "item") {
					const args = arr[1].split(":");
					if (args[args.length-1] >= getRandom(4)) blockitem.makeDropItem(ent, blockitem.buildItem(args[0], args[1], args[2]));
				}
			}
		}
		// 清除boss血条
		if (BossBarMap.has(id)) {
			BossBarMap.get(id).forEach(p => {
				if (p.isOnline()) {
					let pData = BossBarPlayerMap.get(p.name);
					let pDataBossBar = pData[id];
					if (pDataBossBar) {
						p.removeBossBar(pDataBossBar.BossBarId);
					}
				}
				BossBarPlayerMap.delete(p.name);
			})
			BossBarMap.delete(id);
		}
		if (ExistMonsterList[id].length === 2) {
			/*
			addTimeoutTask(new Date().getTime() + 1000, {
				tag: "1秒后检查怪物是否依然存在",
				func: function (beforeHealth, ent, id, name, player){
					let ent_ = entity.getEntityByLevelAndID(server.getLevelByName(MonsterRefreshList[name][4]), id);
					if (ent_) return MonsterHealthCheck(0, ent, player, true);
				},
				args: [0, ent, id, ExistMonsterList[id][1], MonsterObj[id].lateAtker || {isIt: true, name: "unknow"}]
			});*/
			
			const timestamp = new Date().getTime() + 50 * ExistMonsterList[id][0];
			RefreshTaskID[ExistMonsterList[id][1]] = addTimeoutTask(timestamp, {
				tag: "怪物刷新任务",
				func: function (name) {
					delete RefreshTaskID[name];
					let RefreshData = MonsterRefreshList[name];
					if (!RefreshData) {
						return logger.warning("刷怪点错误, 刷新点 " + name + " 不存在.");
					}
					if (!MonsterConfig[RefreshData[0]]) {
						return logger.warning("刷怪点错误, 怪物 " + RefreshData[0] + " 不存在.");
					}
					GenMonster(name, MonsterConfig[RefreshData[0]], RefreshData, true);
				},
				args: [ExistMonsterList[id][1]]
			});
			delete ExistMonsterList[id];
		}
		
		delete MonsterObj[id];
		let attr = database.memoryStorage.getItem("MonsterAttr");
		delete attr[id];
		database.memoryStorage.setItem("MonsterAttr", attr);

		particle.drawEmitter(ent.getPosition(), 'minecraft:death_explosion_emitter');

		ent.kill();
	} else {// 怪物未被击败
		setNPCEntityScoreTag(id, ent, MonsterObj[id]);
		if (data.受伤音效) {
			ent.getPlayersIn(6).forEach(p => {
				entity.makeSoundToPlayer(p, data.受伤音效);
			});
		}
		if (!player.isIt) {
			ent.lookAt(player);
		}
	}
}
/**
 * 解析目标标签
 * @param express {String} 标签
 * @param Monster {Entity} 怪物的实体
 * @return {?Player}
 */
function expressToTarget(express, Monster) {
	const id = entity.getEntityID(Monster);
	if (!MonsterObj[id]) {
		return null;
	}
	const HatredRange = MonsterConfig[MonsterObj[id].info.xname].仇恨范围;
	switch (express) {
		case "@当前目标": {
			if (MonsterObj[id]) {
				return MonsterObj[id].target;
			}
		}
		case "@距离近": {
			let target = Monster.getNearestPlayer(HatredRange);
			if (target === null) {
				return null;
			} else if (target.isAlive()) {
				return target;
			}
		}
		case "@血量少": {
			let playerList = getAlivePlayerList(Monster.getPlayersIn(HatredRange)), target = [false, Infinity];
			playerList.forEach(function (e){
				if (e.getHealth() < target[1]) {
					target = [e, e.getHealth()];
				}
			});
			return target[0];
		}
		case "@console": 
		case "@Console": {
			return server.getConsoleSender();
		}
		case "@s": {
			return Monster;
		}
	}
	return null;
}
function TimeoutExecSkill(Monster, skill, index, SkillName){
	const id = entity.getEntityID(Monster);
	let timeout = 1;
	if (!Boolean(MonsterObj[id])) return;
	if (typeof(skill[index]) === 'string' && skill[index].substr(0, 1) === "!") {// 识别变量技能标识符
		logger.info("Unkonw Skill: "+skill[index]);
	} else {// 固定技能
		const arr = typeof(skill[index]) === 'string' ? skill[index].split(":") : skill[index];
		switch (arr[0]) {
			case "群体消息": 
			case "群体发消息": 
			case "群发消息": {
				if (!arr[3]) {
					return logger.info("技能错误，群体消息内容为空，技能名: " + SkillName);
				}
                debugLog('群体消息：'+JSON.stringify(arr))
				let type = arr[1] || "sendMessage", radius = arr[2], context = arr[3]
				  .replace("{mob.name}", MonsterObj[id].info.xname)
				  .replace("{mob.x}", Monster.getLevel().x)
				  .replace("{mob.y}", Monster.getLevel().y)
				  .replace("{mob.z}", Monster.getLevel().z)
				  .replace("{mob.world}", Monster.getLevel().name);
				if (arr.length > 3) {
					switch(type) {
						case "Tip": {
							type = "sendTip";
							break;
						}
						case "Title": {
							type = "sendTitle";
							break;
						}
						default:
							type = "sendMessage";
					}
				}
                debugLog(type)
				let list = getAlivePlayerList(Monster.getPlayersIn(radius));
                debugLog(list)
				for (let j = 0; j<list.length; j++) {
					list[j][type](context);
				}
				break;
			}
			case "单体消息": {
				if (!arr[3]) {
					return logger.info(SkillName+" 技能出现错误，单体消息内容为空，技能名: "+SkillName);
				}
				let type = arr[1] || "sendMessage", target = expressToTarget(arr[2], Monster), context = arr[3]
				  .replace("{mob.name}", MonsterObj[id].info.xname)
				  .replace("{mob.x}", Monster.getLevel().x)
				  .replace("{mob.y}", Monster.getLevel().y)
				  .replace("{mob.z}", Monster.getLevel().z)
				  .replace("{mob.world}", Monster.getLevel().name);
				if (arr.length > 3) {
					switch(type) {
						case "Tip": {
							type = "sendTip";
							break;
						}
						case "Title": {
							type = "sendTitle";
							break;
						}
						default:
							type = "sendMessage";
					}
				}
				if (target) target[type](context);
				break;
			}
			case "执行命令": {// 执行命令:@当前目标:say 1
				let executor = arr[1] ? expressToTarget(arr[1], Monster) : Monster;
				if (!executor) {
					break;
				}
				const commandSender = arr[1] === '@Console' ? server.getConsoleSender() : (new ExecutorCommandSender(server.getConsoleSender(), executor, executor.getLocation()));
				server.getScheduler().scheduleDelayedTask(() => server.dispatchCommand(commandSender, arr[2]), 0);
				break;
			}
			case "单体药水效果": {
				let target = expressToTarget(arr[1], Monster);
				if (target) {
					server.getScheduler().scheduleDelayedTask(() => server.dispatchCommand(server.getConsoleSender(), 'effect "'+target.getName()+'" '+arr[2]), 0);
				}
				break;
			}
			case "群体药水效果": {
				let list = getAlivePlayerList(Monster.getPlayersIn(arr[1]));
				for (var j = 0; j<list.length; j++) {
					const cmd = 'effect "'+list[j].getName()+'" '+arr[2];
					server.getScheduler().scheduleDelayedTask(() => server.dispatchCommand(server.getConsoleSender(), cmd), 0);
				}
				break;
			}
			case "转移仇恨目标": {
				if (MonsterObj[entity.getEntityID(Monster)]) {
					MonsterObj[entity.getEntityID(Monster)].target = expressToTarget(arr[1], Monster);
				}
				break;
			}
			case "单体雷击": {
				let target = expressToTarget(arr[1], Monster);
				if (target) {
					Java.type('cn.nukkit.entity.Entity').createEntity(93, target.getPosition());
				}
				addTimeoutTask(new Date().getTime()+500, {
					func: function (Monster){Monster.setOnFire(0);},
					args: [Monster]
				});
				break;
			}
			case "群体雷击": {
				let list = getAlivePlayerList(Monster.getPlayersIn(arr[1]));
				let ent = Java.type('cn.nukkit.entity.Entity');
				for (var i = 0; i<list.length; i++) {
					ent.createEntity(93, list[i].getPosition());
				}
				addTimeoutTask(new Date().getTime()+500, {
					func: function (Monster){Monster.setOnFire(0);},
					args: [Monster]
				});
				break;
			}
			case "单体击飞": {
				let target = expressToTarget(arr[1], Monster);
                if (target === false) break;
				try {
					target.setMotion(target.getLocation().getDirectionVector().multiply(-1).add(0, 0.5*arr[2], 0));
				} catch (err) {
					console.log("单体击飞 错误:"+arr[1]+" | target:"+String(target));
				}
				break;
			}
			case "群体击飞": {
				let list = getAlivePlayerList(Monster.getPlayersIn(arr[1]));
				for (var i = 0; i<list.length; i++) {
					list[i].setMotion(list[i].getLocation().getDirectionVector().multiply(-1).add(0, 0.5*arr[2], 0));
				}
				break;
			}
			case "单体伤害": {
				let player = expressToTarget(arr[1], Monster);
				if (player) {
					var PlayerHealth;
					var target = {MaxH: 0};
					if (RSHealthAPI){
						PlayerHealth = RSHealthAPI.getPlayerHealth(player);
						target.MaxH = PlayerHealth.getMaxHealth();
						target.H = PlayerHealth.getHealth();
					} else {
						target.MaxH = player.getMaxHealth();
						target.H = player.getHealth();
					}
					if (arr[2].substr(0, 1) === "!") {
						target.H -= eval(arr[2].substr(1));
					} else {
						target.H -= arr[2];
					}
					if (isNaN(target.H)) {
						target.H = 0;
						logger.info(SkillName+" 技能出现错误: "+arr.join(":")+",value: "+target.H);
					}
					if (RSHealthAPI){
						PlayerHealth.setHealth(target.H < 1 ? 0 : target.H);
					} else {
						player.setHealth(target.H < 1 ? 0 : target.H);
					}
					entity.makeSoundToPlayer(player, "GAME_PLAYER_HURT");
				}
				break;
			}
			case "群体伤害": {
				let list = getAlivePlayerList(Monster.getPlayersIn(arr[1]));
				for (var i = 0; i<list.length; i++) {
					var PlayerHealth;
					var target = {MaxH: 0};
					if (RSHealthAPI){
						PlayerHealth = RSHealthAPI.getPlayerHealth(list[i]);
						target.MaxH = PlayerHealth.getMaxHealth();
						target.H = PlayerHealth.getHealth();
					} else {
						target.MaxH = list[i].getMaxHealth();
						target.H = list[i].getHealth();
					}
					if (String(arr[2]).substr(0, 1) === "!") {
						target.H -= eval(arr[2].substr(1));
					} else {
						target.H -= arr[2];
					}
					if (isNaN(target.H)) {
						target.H = 0;
						logger.info(SkillName+" 技能出现错误: "+arr.join(":")+", value: "+target.H)
					}
					if (RSHealthAPI){
						PlayerHealth.setHealth(target.H < 1 ? 0 : target.H);
					} else {
						list[i].setHealth(target.H < 1 ? 0 : target.H);
					}
					entity.makeSoundToPlayer(list[i], "GAME_PLAYER_HURT");
				}
				break;
			}
			case "恢复": {
				let me = {H: entity.getEntityHealth(Monster), MaxH: entity.getEntityMaxHealth(Monster)}, addheal = 0;
				if (arr[1].substr(0, 1) === "!") {
					addheal = Number(eval(arr[1].substr(1)));
				} else {
					addheal = Number(arr[1]);
				}
				if (isNaN(addheal)) {
					logger.info(SkillName+" 技能出现错误: "+arr.join(":")+",value: "+me.H);
				} else {
					Monster.heal(addheal);
					setNPCEntityScoreTag(entity.getEntityID(Monster), Monster, MonsterObj[entity.getEntityID(Monster)]);
				}
				break;
			}
			case "更改属性": {
				let argsV = skill[index].substr(5);
				let attrId = "NMonster";
				if (argsV) {
					try {
						argsV = JSON.parse(argsV);
					} catch(err) {
						logger.info(SkillName+" 技能出现错误: "+arr.join(":"));
						break;
					}
					if (typeof(argsV) != "object") break;
					if (argsV.attrId) {
						attrId = argsV.attrId;
						delete argsV.attrId;
					}
				} else {
					break;
				}
				SetMonsterAttr(entity.getEntityID(Monster), attrId, argsV);
				break;
			}
			case "单体音效": {
				let target = expressToTarget(arr[1], Monster);
				if (target) {
					entity.makeSoundToPlayer(target, arr[2]);
				}
				break;
			}
			case "群体音效": {
				let list = getAlivePlayerList(Monster.getPlayersIn(arr[1]));
				for (var i = 0; i<list.length; i++) {
					entity.makeSoundToPlayer(list[i], arr[2]);
				}
				break;
			}
			case "睡眠": {
				timeout = Number(arr[1]);
				break;
			}
			case "召唤": {// 召唤:怪物名
				const data =  MonsterConfig[arr[1]];
				const entPos = Monster.getPosition();
				if (data) {
					GenMonster("", data, [arr[1], entPos.x, entPos.y, entPos.z, Monster.getLevel().getName()], false);
				} else {
					logger.info(SkillName+" 技能出现错误: "+arr.join(":")+",不存在的怪物名: "+arr[1]);
				}
				break;
			}
			case "传送至目标身后": {// 传送至目标身后
				if (MonsterObj[id].target) {
					MonsterObj[id].target.teleport(Monster.add(0, 0.3));
					
				}
				break;
			}
			case "点燃": {// 点燃:@当前目标:时间s
				let player = expressToTarget(arr[1], Monster);
				if (player) {
					player.setOnFire(arr[2] || 7);
				}
				break;
			}
			case "互换位置": {
				let player = expressToTarget(arr[1], Monster);
				if (player) {
					let targetPos = player.getPosition();
					player.teleport(Monster.add(0, 0.3));
					Monster.teleport(targetPos);
				}
				break;
			}
			case "攻击": {
				let player = expressToTarget(arr[1], Monster);
				if (player) {
					Monster.hit(player);
					const data =  MonsterConfig[arr[1]];
					if (data && data.打击音效) {
						blockitem.makeSound(player, data.打击音效);
					}
				}
				break;
			}
			case "执行命令": {// 执行命令:@当前目标:say 1
				let executor = arr[1] ? expressToTarget(arr[1], Monster) : Monster;
				if (!executor) {
					break;
				}
				const commandSender = new ExecutorCommandSender(server.getConsoleSender(), executor, executor.getLocation());
				server.getScheduler().scheduleDelayedTask(() => server.dispatchCommand(commandSender, arr[2]), 0);
				break;
			}
			default: {
				logger.info("Unkonw Skill: "+skill[index]);
			}
		}
	}
	if (index < skill.length-1) {
		if (timeout > 1) {
			addTimeoutTask(new Date().getTime() + 50*timeout, {
				tag: "执行 "+SkillName+" 技能，i:"+(index+1),
				func: TimeoutExecSkill,
				args: [Monster, skill, index+1, SkillName]
			});
		} else {
			TimeoutExecSkill(Monster, skill, index+1, SkillName);
		}
	}
}
/**
 * 将 未打孔物品 转为 有孔符文槽 的物品
 * 或设置物品符文槽数
 * @param SkillName {String} 技能名字
 * @param Monster {Entity} 释放技能的实体
 * @returns {Boolean} 是否执行成功
 */
function ExecSkill(SkillName, Monster){
	let skill = SkillConfig[SkillName];
	if (skill) {
		manager.concurrentRun("TimeoutExecSkill", Monster, skill, 0, SkillName);
		return true;
	} else {
		logger.warning("不存在的技能: "+SkillName);
		return false;
	}
}
function NPCTickCallback(ent) {
	const id = entity.getEntityID(ent);
	if (MonsterObj[id] === undefined) return;
	let data = MonsterConfig[MonsterObj[id].info.xname];
	if (data === undefined) return;
	let entPos = ent.getPosition();

	// TODO: 处理巡回的移动
	if (MonsterObj[id].currentTour) {
		// more code...
		const distance = MonsterObj[id].currentTour.distance(ent);
	}

	// 处理随机移动
	if (MonsterObj[id].strollTick != undefined && !MonsterObj[id].target) {
		if (MonsterObj[id].strollTick) {
			MonsterObj[id].strollTick --;
		} else {
			MonsterObj[id].strollTick = getRandomRange(5, 20) * 20;
			let pos = getNode(entPos, 6);
			if (pos) {
				ent.stopMove();
				ent.lookAt(pos);
				ent.findAndMove(pos);
			} else {
				ent.teleport(MonsterObj[id].info.pos);
			}
		}
	}

	// 方块碰撞箱实现
	if (ent.getMotion().x != 0 && ent.getMotion().y != 0 && ent.getMotion().z != 0) {
		if (blockitem.getBlock(entPos.add(ent.motionX + ent.getWidth()/2)).isSolid()) {
			ent.motionX = -ent.motionX/1.5;
		}
		/*if (blockitem.getBlock(entPos.add(0, ent.motionY)).isSolid()) {
			ent.motionY = 0;
		}*/
		if (blockitem.getBlock(entPos.add(0, 0, ent.motionZ + ent.getWidth()/2)).isSolid()) {
			ent.motionZ = -ent.motionZ/1.5;
		}
	}

	for (let i in MonsterObj[id].skill) {
		for (let j = 0; j < MonsterObj[id].skill[i].length; j++) {
			if (MonsterObj[id].skill[i][j] > 0) {
				// 技能时刻递减
				MonsterObj[id].skill[i][j] --;
				// 时刻技能处理
				if (i === "时刻技能" && MonsterObj[id].skill[i][j] < 1) {
					const arr = data[i][j].split(":");
					MonsterObj[id].skill[i][j] = arr[0];
					ExecSkill(arr[1], ent);
				}
			} else {
				break;
			}
		}
	}
	if (MonsterObj[id].second) {
		MonsterObj[id].second --;
	} else {
		// 每秒生命恢复
		const attr = GetMonsterAttr(id);
		if (!isNaN(attr.每秒恢复)) {
			let h = ent.getHealth();
			if (h < MonsterObj[id].info.maxhealth) {
				h += Number(attr.每秒恢复);
				if (h > MonsterObj[id].info.maxhealth) {
					h = MonsterObj[id].info.maxhealth;
				}
				ent.heal(h);
				setNPCEntityScoreTag(id, ent, MonsterObj[id]);
			}
		}
		MonsterObj[id].second = 20;
	}
	// 回调刻处理
	MonsterObj[id].callTick ++;
	if (MonsterObj[id].callTick < data.回调刻) {
		return;
	}
	MonsterObj[id].callTick = 0;

	if (MonsterObj[id].attackTick > 0) {
		MonsterObj[id].attackTick -= data.回调刻;
	}
	// 被攻击判断
	let isUnderAttack = false;
	if (MonsterObj[id].underAttack && data.击退) {
		if (new Date().getTime() > MonsterObj[id].underAttack) {
			MonsterObj[id].underAttack = 1;
		} else {
			isUnderAttack = true;
		}
	}

	// 被攻击时逃跑
	if (MonsterObj[id].eludeTick != undefined) {
		if (isUnderAttack) {
			MonsterObj[id].eludeTick = getRandomRange(3, 6) * 20;
			let pos = getNode(MonsterObj[id].target || entPos, 10);
			if (pos) {
				MonsterObj[id].target = false;
				ent.stopMove();
				ent.lookAt(pos);
				ent.findAndMove(pos);
			}
		} else if (MonsterObj[id].eludeTick > -1) {
			MonsterObj[id].eludeTick -= data.回调刻;
			return;
		}
	}

	// 脱战回血
	if (data.脱战回血 && MonsterObj[id].backspawn === -1) {
		const arr = data.脱战回血.split(":");
		if (arr[0] > MonsterObj[id].notfighting) {
			MonsterObj[id].notfighting ++;
		} else if (entity.getEntityHealth(ent) < entity.getEntityMaxHealth(ent)) {
			ent.heal(Number(arr[1])*data.回调刻);
			setNPCEntityScoreTag(id, ent, MonsterObj[id]);
		}
	}
	// 被动攻击模式
	if (data.主动攻击 === false && MonsterObj[id].target === false) {
		return;
	}
	// 仇恨范围
	if (data.仇恨范围 === undefined) {
		return;
	}
	// 判断返回重生点刻进行返回
	if (MonsterObj[id].backspawn >= data.返回重生点刻) {
		MonsterObj[id].backspawn = -1;
		MonsterObj[id].target = false;
		return ent.teleport(MonsterObj[id].info.pos);
	}
	const playerlist = getAlivePlayerList(ent.getPlayersIn(data.仇恨范围));
	if (MonsterObj[id].target) {
		const targetDist = ent.distance(MonsterObj[id].target),// 怪物与目标的直线距离
			currentDist = ent.distance(MonsterObj[id].info.pos);// 怪物距重生点的距离
		if (playerlist.length > 0 && MonsterObj[id].attackTick < 1) {
			let hasAttack = false;
			if (data.攻击模式 === "单个目标") {
				if (targetDist <= data.攻击范围) {
					ent.hit(MonsterObj[id].target);
					hasAttack = true;
				}
			} else if (data.攻击模式 === "范围打击") {
				const list = ent.getPlayersIn(data.攻击范围);
				for (let i = 0; i<list.length; i++){
					ent.hit(list[i]);
					hasAttack = true;
				}
			} else if (data.攻击模式 === "远程攻击") {
				if (targetDist <= data.攻击范围) {
					hasAttack = true;
					let pos1 = ent.getPosition();
					let pos2 = MonsterObj[id].target.getPosition();
					let start = pos1.add((pos1.x > pos2.x ? -0.5 : 0.5), 2, (pos1.z > pos2.z ? -0.5 : 0.5));
					let arrow = entity.shootArrow(start, pos2.add(0, 1.6, 0), ent, false, 1.7*targetDist/10);
					MonsterSendOfProjectile[entity.getEntityID(arrow)] = entity.getEntityID(ent);
				}
			} else if (data.攻击模式 === "不攻击") {
				//
			}
			if (hasAttack) {
				MonsterObj[id].attackTick = data.攻击间隔;
				if (data.打击音效) {
					blockitem.makeSound(MonsterObj[id].target, data.打击音效);
				}
				for (let i = 0, length = MonsterObj[id].skill["打击技能"].length; i < length; i++) {
					if (MonsterObj[id].skill["打击技能"][0] < 1) {
						// 打击技能处理
						const arr = data["打击技能"][i].split(":");
						MonsterObj[id].skill["打击技能"][i] = arr[0];
						ExecSkill(arr[1], ent);
					}
				}
			}
		}
		// 目标
		if (data.跟踪范围 > 1){// 跟踪范围处理 怪物以重生点为圆心的范围
			// if 怪物当前距离超过跟踪范围
			// else 目标超出跟踪范围
			if (currentDist >= data.跟踪范围) {
				MonsterObj[id].target = false;
			} else if (MonsterObj[id].target.distance(MonsterObj[id].info.pos) >= data.跟踪范围) {
				MonsterObj[id].target = false;
			}
		}
		let target = MonsterObj[id].target;
		if (target) {// 仇恨范围处理 怪物以自身为圆心的范围
			// if 判断玩家是否在线
			// else 判断游戏模式
			// else 判断是否活着
			// else 与目标的距离超出仇恨范围
			if (isPlayer(target)) {
				if (!target.isOnline()) {
					MonsterObj[id].target = false;
				} else if (Config.playerlist.PlayerMode.indexOf(manager.getPlayerGameMode(target)) === -1) {
					MonsterObj[id].target = false;
				}
			} else {
				if (!target.isAlive()) {
					MonsterObj[id].target = false;
				} else if (targetDist > data.仇恨范围) {
					MonsterObj[id].target = false;
				}
			}
		}
		target = MonsterObj[id].target;
		// 目标跟踪
		if (target) {
			// 重置返回重生点刻
			if (MonsterObj[id].backspawn === -1) {
				MonsterObj[id].backspawn = 0;
				MonsterObj[id].notfighting = 0;
			}
			ent.lookAt(target);
			ent.stopMove();
			if (isUnderAttack) {
				MonsterObj[id].backspawn = 0;
			} else if (data.攻击模式 === "不攻击") {
				MonsterObj[id].backspawn = 0;
			} else if (data.攻击模式 === "远程攻击" && targetDist <= data.攻击范围) {
				if (MonsterObj[id].projectileMiss) {
					// 处理拉进距离的移动
					if (targetDist > 3) {
						ent.findAndMove(target.getPosition());
					}
				} else if (targetDist <= data.攻击范围-3) {
					// 处理远程攻击拉开距离的移动
					let pos1 = ent.getPosition();// 怪物的位置
					let pos2 = target.getPosition();// 目标的位置
					const arr = [pos1.x > pos2.x ? 1 : -1, pos1.z > pos2.z ? 1 : -1];
					let list = [pos1.add(arr[0], 0, arr[1]), pos1.add(arr[0]), pos1.add(0, 0, arr[1])]
					for (let i = 0; i < list.length; i++) {
						let pos = false;
						for (let k = -1; k < 2; k++) {
							if (isCanMove(list[i].add(0, k))) {
								pos = list[i].add(0, k);
								break;
							}
						}
						if (pos) {
							ent.directMove(pos);
							break;
						}
					}
				}
				MonsterObj[id].backspawn = 0;
			} else if (ent.findAndMove(target.getPosition())) {
				MonsterObj[id].backspawn = 0;
			} else {
				MonsterObj[id].backspawn++;
			}
		}
	} else {
		if (MonsterObj[id].backspawn > -1) {
			ent.stopMove();
			MonsterObj[id].backspawn++;
		}
		// 尝试更改为最近的可跟踪目标
		if (playerlist[0]) {
			MonsterObj[id].target = playerlist[0];
		} else {
			MonsterObj[id].target = false;
		}
	}
}
function EntityDeathEvent(event) {//实体死亡事件，用于处理怪物掉落物
	let ent = event.getEntity();
	if (ent.getName() != "BNNPC" || ent.getName() != "VanillaNPC") {
		return;
	}
	const id = entity.getEntityID(ent);
	if (!ExistMonsterList[id]) return;
	event.setDrops(Java.to([], "cn.nukkit.item.Item[]"));
}
function EntityDamageByEntityEvent(event) {
	if (event.getEventName() === "cn.nukkit.event.entity.EntityDamageEvent" || event.getEventName() === "cn.nukkit.event.entity.EntityDamageByBlockEvent") return;
	if (event.isCancelled()) {
		return;
	}
	let Wounded = event.getEntity();//被攻击者
	let Damager = event.getDamager();//攻击者
	if (Wounded.getName() === "BNNPC" || Wounded.getName() === "VanillaNPC") {
		const id = entity.getEntityID(Wounded);
		if (!MonsterObj[id]) return;
		if (Damager instanceof Java.type("cn.nukkit.entity.Entity")) {
			if (!blockitem.getBlock(Wounded.getPosition()).isSolid() && MonsterObj[id].underAttack) {// 是站在空地上并且underAttack不为0
				Wounded.stopMove();
				entity.setEntityPosition(Wounded, Wounded.getPosition().add(0, 0.55, 0));
			}
			// 玩家击退怪物
			MonsterObj[id].underAttack = new Date().getTime() + 400;
		}
	} else if (Damager.getName() === "BNNPC" || Damager.getName() === "VanillaNPC") {
		const id = entity.getEntityID(Damager);
		if (NWeapon) return;
		const attr = GetMonsterAttr(id);
		event.setDamage(event.getDamage() + attr.攻击力-1);
	}
}
// 处理弓箭
function ProjectileHitEvent(event) {
	let arrow = event.getEntity();
	const monsterId = MonsterSendOfProjectile[entity.getEntityID(arrow)];
	delete MonsterSendOfProjectile[entity.getEntityID(arrow)];
	addTimeoutTask(1, {
		func: function (arrow){
			let obj = MonsterObj[monsterId];
			if (!obj) return;
			if (arrow.isClosed()) {
				MonsterObj[monsterId].projectileMiss = false;
				return;
			}
			if (arrow.getPosition().y > Math.floor(arrow.getPosition().y)+0.1) {
				MonsterObj[monsterId].projectileMiss = false;
			} else {
				MonsterObj[monsterId].projectileMiss = true;
			}
			arrow.close();
		},
		args: [arrow, monsterId]
	});
}

// 配置文件加载
function loadConfig() {
	// 加载Config文件
	Config = JSON.parse(manager.YAMLtoJSON(manager.readFile('./plugins/BlocklyNukkit/NMonster/Config.yml')));
	// 加载怪物列表
	MonsterConfig = {};
	let list = getFileList("./plugins/BlocklyNukkit/NMonster/怪物/");
	for (var i = 0; i < list.length; i++) {
		let file = list[i];
		let data = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/NMonster/怪物/" + file.getName())));
		// 怪物配置校正
		if (!data.回调刻 || data.回调刻 < 1) {
			data.回调刻 = 3;
		}
		if (!data.返回重生点刻) {
			data.返回重生点刻 = 3;
		}
		//delete data["受击粒子方块ID"];
		//data.属性.命中率 = .05;
		//manager.writeFile("./plugins/BlocklyNukkit/NMonster/怪物/" + file.getName(), manager.JSONtoYAML(JSON.stringify(data)));
		MonsterConfig[file.getName().split(".yml")[0]] = data;
	}
	// 加载技能列表
	SkillConfig = {};
	let SkillList = getFileList("./plugins/BlocklyNukkit/NMonster/技能/");
	for (let i = 0; i < SkillList.length; i++) {
		let file = SkillList[i];
		let data = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/NMonster/技能/" + file.getName()))).技能;
		SkillConfig[file.getName().split(".yml")[0]] = data;
	}
	// 加载刷新点
	var worldList_ = manager.getFolderFiles("./worlds/"), worldList = [];
	for (let i = 0; i<worldList_.length; i++) {
		worldList.push(worldList_[i]);
	}
	MonsterRefreshList = JSON.parse(manager.YAMLtoJSON(manager.readFile("./plugins/BlocklyNukkit/NMonster/刷怪点.yml")));
	for (let i in MonsterRefreshList) {
		if (!MonsterConfig[MonsterRefreshList[i][0]]) {
			logger.warning("刷怪点错误, 怪物 " + MonsterRefreshList[i][0] + " 不存在.");
			continue;
		}
		GenMonster(i, MonsterConfig[MonsterRefreshList[i][0]], MonsterRefreshList[i], false, worldList);
	}
	// 读取NBT掉落物
	NBTItemData = JSON.parse(manager.readFile("./plugins/BlocklyNukkit/NMonster/NBT掉落物.json"));
}

// - 功能性函数
function setNPCEntityScoreTag(id, ent, config) {
	const info = config.info;
	entity.setEntityName(ent, (info.name+"§r")
		.replace("{health}", ent.getHealth().toFixed(1))
		.replace("{maxhealth}", info.maxhealth)
		.replace("{healthbar}", getProgressBar(ent.getHealth(), info.maxhealth)));
	if (info.showname) ent.setScoreTag(info.showname
		.replace("{health}", ent.getHealth().toFixed(1))
		.replace("{maxhealth}", info.maxhealth)
		.replace("{healthbar}", getProgressBar(ent.getHealth(), info.maxhealth)));
	updateBossBar(id, ent, config);
}
const BossBarColor = Java.type('cn.nukkit.utils.BossBarColor');
const BossBarMap = new Map();//  key: entityId | value: Array<...player>
const BossBarPlayerMap = new Map();// key: playerName | value: {123(entId): {percent: 20, BossBarId: 124187609}}

function updateBossBar(id, ent, config, isClear) {
	const ConfigFile = MonsterConfig[config.refreshName];
	if (!ConfigFile.Boss血条) {// TODO: 此处用于更新boss血条
		return;
	}
	const showRange = ConfigFile.Boss血条.showRange || 150;
	const title = ConfigFile.Boss血条.style
	.replace("{mob.name}", config.info.xname)
	.replace("{mob.x}", ent.getLevel().x)
	.replace("{mob.y}", ent.getLevel().y)
	.replace("{mob.z}", ent.getLevel().z)
	.replace("{mob.world}", ent.getLevel().name)
	.replace("{health}", ent.getHealth().toFixed(1))
	.replace("{maxhealth}", config.info.maxhealth) || config.info.xname;
	const percent = Math.ceil((ent.getHealth() / config.info.maxhealth) * 100);
	const color = percent > 25 ? percent > 70 ? BossBarColor.GREEN : BossBarColor.YELLOW : BossBarColor.RED;
	const players = ent.getPlayersIn(showRange);
	if (BossBarMap.has(id)) {// 如果实体曾经存在
		const currentList = [];
		if (!isClear) {
            players.forEach(v => currentList.push(v.name));
        }
		const afterList = BossBarMap.get(id);
		for (let p of afterList) {
			const index = currentList.indexOf(p.name);
			if (index > -1) {// 如果之前的玩家存在于当前列表，则更新玩家bossbar
				if (!BossBarPlayerMap.has(p.name)) continue;// 不存在Map则下一个
				let pData = BossBarPlayerMap.get(p.name);
				currentList[index] = null;
				let pDataBossBar = pData[id];
				if (pDataBossBar) {
					if (pDataBossBar.percent === percent) continue;// 如果血条没变就遍历下一个
					pDataBossBar.percent = percent;
					debugLog('更新'+p.name+'的bossbar');
					p.updateBossBar(title, percent, pDataBossBar.BossBarId);
					const bossbar = p.getDummyBossBar(pDataBossBar.BossBarId);
					if (!bossbar) {
						BossBarPlayerMap.delete(p.name);
						continue;
					}
					bossbar.setColor(color);
				}
			} else {// 之前的玩家不存在于当前列表中，则移除玩家bossbar
				if (p.isOnline()) {
					let pData = BossBarPlayerMap.get(p.name);
					let pDataBossBar = pData[id];
					if (pDataBossBar) {
						debugLog('移除'+p.name+'的bossbar，之前的玩家不存在于当前列表');
						p.removeBossBar(pDataBossBar.BossBarId);
					}
				}
				BossBarPlayerMap.delete(p.name);
			}
		}
		currentList.forEach(name => {// 向范围内的新玩家创建bossbar
			if (!name) return;
			const p = server.getPlayer(name);
			debugLog('向'+name+'创建新的bossbar，不存在于当前列表');
			/**
			 * bossbar的id
			 * @type {number}
			 */
			const uid = p.createBossBar(title, percent);
			p.getDummyBossBar(uid).setColor(color);
			let pDataBossBar = BossBarPlayerMap.get(p.name);
			if (pDataBossBar) {
				pDataBossBar[id] = {percent: percent, BossBarId: uid};
			}
			let data = {};
			data[id] = {'percent': percent, 'BossBarId': uid};
			BossBarPlayerMap.set(p.name, data);
		});
	} else {
		players.forEach(p => {
			debugLog('向'+p.name+'创建新的bossbar，怪物不存在于Map');
			const uid = p.createBossBar(title, percent);
			p.getDummyBossBar(uid).setColor(color);
			let pDataBossBar = BossBarPlayerMap.get(p.name);
			if (pDataBossBar) {
				pDataBossBar[id] = {percent: percent, BossBarId: uid};
			}
			let data = {};
			data[id] = {'percent': percent, 'BossBarId': uid};
			BossBarPlayerMap.set(p.name, data);
		})
	}
	BossBarMap.set(id, players);

}
function getPosition(args, x, y, z) {
	let position = args;
	if (args instanceof Java.type("cn.nukkit.level.Position")) {// 如果是Position方法
		position = [];
		position[0] = x ? args.x + x: args.x;
		position[1] = y ? args.y + y : args.y;
		position[2] = z ? args.z + z : args.z;
		position[3] = args.getLevel().getName();
	}
	return Java.type("cn.nukkit.level.Position").fromObject(manager.buildvec3(position[0], position[1], position[2]), server.getLevelByName(position[3]));
}
function getRandom(number) {
	return String(Math.random()).substr(3, number) - 0 + 1;
}
function getRandomRange(min, max) {
	return Math.floor(Math.random()*(max-min+1)+min);
}
function Date2YMD(t){
	if (typeof t === "string") {
		t = new Date(t);
	} else if (typeof t === "number") {
		t = new Date(t);
	}
	return (t.getHours() < 10 ? "0"+t.getHours() : t.getHours())+':'+(t.getMinutes() < 10 ? "0"+t.getMinutes() : t.getMinutes())+':'+(t.getSeconds() < 10 ? "0"+t.getSeconds() : t.getSeconds());
}
function getProgressBar(i, maxi){
	let value = i / maxi;
	let arr = "|||||||||||||||||||||||||".split("");
	value = Math.ceil(value * arr.length);
	arr.splice(value, 0, "§c");
	return "§a" + arr.join("") + "§r";
}
// 获取有效玩家列表
function getAlivePlayerList(list){
	let playerlist = [];
	for (var i = 0; i<list.length; i++) {
		let gamemode = manager.getPlayerGameMode(list[i]);
		if (list[i].isAlive()) {// 获取玩家是否活着
			if (Config.playerlist && Config.playerlist.PlayerMode.indexOf(gamemode) === -1){// 判断游戏模式
				continue;
			}
			playerlist.push(list[i]);// 添加至列表
		}
	}
	return playerlist;
}

// 复活悬浮字倒计时
var RefreshTimeList = {};
manager.setInterval(function (){
	for (let i in RefreshTimeList) {
		RefreshTimeList[i].t -= 20;
		if (RefreshTimeList[i].t > 0) {
			let point = MonsterRefreshList[i];
			let pos = Java.type("cn.nukkit.level.Position").fromObject(manager.buildvec3(point[1], point[2] + 1, point[3]), server.getLevelByName(point[4]));
			const str = point[0]+" "+TickToTime(RefreshTimeList[i].t);
			if (RefreshTimeList[i].e) {
				entity.setEntityName(RefreshTimeList[i].e, str);
			} else {
				let FloatText = entity.buildFloatingText(str, pos, 5, F(function(){}));
				entity.startDisplayFloatingText(FloatText);
				RefreshTimeList[i].e = FloatText;
			}
		} else if (RefreshTimeList[i].e) {
			entity.removeEntity(RefreshTimeList[i].e);
			delete RefreshTimeList[i];
		} else {
			logger.info("复活悬浮字倒计时 "+i+"，出现了一个不可思议的错误 "+JSON.stringify(RefreshTimeList[i]));
		}
	}
}, 20);
function TickToTime(tick){
	let back = [0, 0, 0, tick];
	if (tick > 20) {
		back[3] = tick % 20;
		tick = tick - back[3];
		back[2] = Math.floor(tick/20);
		if (back[2] > 59) {
			back[1] = Math.floor(back[2]/60);
			back[2] = back[2] % 60;
			if (back[1] > 59) {
				back[0] = Math.floor(back[1]/60);
				back[1] = back[1] % 60;
			}
		}
	}
	for (let i = 0; i<back.length-1; i++) back[i] = FormatZero(back[i], 2);
	return back[0]+":"+back[1]+":"+back[2]
	//+"."+back[3];
}
function FormatZero(num, len) {
	if (new String(num).length > len) return num;
	return (new Array(len).join(0) + num).slice(-len);
}
function isPlayer(entity) {
	return entity instanceof Java.type("cn.nukkit.Player");
}
// 判断位置是否可以移动
function isCanMove(pos) {
	let y1 = blockitem.getBlock(pos.add(0, -1));
	let y2 = blockitem.getBlock(pos);
	let y3 = blockitem.getBlock(pos.add(0, 1));
	let y4 = blockitem.getBlock(pos.add(0, 2));
	let list = [y1, y2, y3, y4];
	let res = [y1.isSolid(), y2.isSolid(), y3.isSolid(), y4.isSolid()];
	if (["Fence", "Wall"].indexOf(y1.getName().split(" ")[1]) > -1) {
		// 若y1为 栅栏、墙 则设置y2的res为true
		res[1] = true;
	}
	for (let i = 0; i< list.length; i++) {
		if (["Door", "Trapdoor"].indexOf(list[i].getName().split(" ")[1]) > -1) {
			// 若y1为 门、活板门 则设置为false
			res[i] = false;
		}
	}
	if (res[0] && !res[1] && !res[2]) {
		return true;
	}
	return false;
}
// 排序
function compare(porp){
	return function(a, b){
		var v1 = a[porp];
		var v2 = b[porp];
		return v2 - v1;
	}
}
function getEntityBox(type) {
	switch (type) {
		case 10: {// 鸡
			return [0.4, 0.7];
		}
		case 11: {// 牛
			return [0.45, 1.4];
		}
		case 12: {// 猪
			return [0.9, 0.9];
		}
		case 13: {// 羊
			return [0.9, 1.3];
		}
		case 14: {// 狼
			return [0.6, 0.8];
		}
		case 20: {// 铁傀儡
			return [1.4, 2.8];
		}
		case 26: {// 骷髅马
			return [1.4, 1.6];
		}
		case 32: {// 僵尸
			return [0.6, 1.95];
		}
		case 34: {// 骷髅
			return [0.6, 1.99];
		}
		case 35: {// 蜘蛛
			return [1.4, 0.9];
		}
		case 36: {// 僵尸猪人
			return [0.6, 1.95];
		}
		case 40: {// 洞穴蜘蛛
			return [0.7, 0.5];
		}
		case 48: {// 凋零骷髅
			return [0.7, 1.9];
		}
        case 105: {
            return [0.8, 0.4];
        }
		default: {
			return [];
		}
	}
}
// 寻路部分！！！
function getNextPosList(p) {
	//获取下一个点的列表
	var arr = [];
	arr.push(p.add(-1));
	arr.push(p.add(1));
	arr.push(p.add(0, 0, -1));
	arr.push(p.add(0, 0, 1));
	arr.push(p.add(-1, 1));
	arr.push(p.add(1, 1));
	arr.push(p.add(0, 1, -1));
	arr.push(p.add(0, 1, 1));
	arr.push(p.add(-1, -1));
	arr.push(p.add(1, -1));
	arr.push(p.add(0, -1, -1));
	arr.push(p.add(0, -1, 1));
	return arr;
}
function getStringPos(pos) {
	return [pos.x, pos.y, pos.z].join(" ");
}
function getParticlePos(pos) {
	return pos.floor().add(0.5, 0, 0.5);
}
function getEstmateCost(pos1, pos2) {
	// 获取预估代价
	return Math.abs(pos1.x - pos2.x) + Math.abs(pos1.y - pos2.y) + Math.abs(pos1.z - pos2.z);
}
function getNode(start, length, maxStep) {
	var maxStep = maxStep || length*3;
	var VisitedNode = [getStringPos(start)];
	var nextPosList = getNextPosList(start);
	var moveNode = [false];// 移动的坐标节点路径点
	var n = 0;
	var isEnd = false;
	var endPos = [0, false];
	while(maxStep) {
		n ++;
		var tempData = [0, false];
		var tempNode = [];
		for (var i = 0; i < nextPosList.length; i++) {
			if (VisitedNode.indexOf(getStringPos(nextPosList[i])) > -1) {
				continue;
			}
			if (isCanMove(nextPosList[i])) {
				tempNode.push(nextPosList[i]);
			}
		}
		switch (tempNode.length) {
			case 0:
				break;
			case 1: {
				tempData = [getEstmateCost(start, tempNode[0]), tempNode[0]];
				break;
			}
			default: {
				let pos = tempNode[getRandomRange(0, tempNode.length-1)];
				tempData = [getEstmateCost(start, pos), pos];
			}
		}

		if (tempData[0] > length) {
			isEnd = true;
			endPos = [length, tempData[1]];
		} else if (tempData[0] > endPos[0]) {
			endPos = tempData;
		}

		if (n > maxStep) {// 失败，演算次数超出预期
			break;
		}
		if (tempData[1] === false) {
			moveNode.length = moveNode.length-1;
			if (moveNode.length > 1) {
				n -= 2;
				nextPosList = getNextPosList(moveNode[moveNode.length-1]);
			} else {// 失败，没有到达预计 length
				break;
			}
		} else {
			//particle.drawDot(getParticlePos(tempData[1]), 18, 0, 255, 0, server.getPlayer("mcayear"));
			VisitedNode.push(getStringPos(tempData[1]));
			moveNode.push(tempData[1]);
			if (isEnd) {
				moveNode[0] = true;
				break;
			}
			nextPosList = getNextPosList(tempData[1]);
		}
	}
	//logger.info(getStringPos(start)+" to "+getParticlePos(endPos[1]));
	return endPos[1] === false ? false : getParticlePos(endPos[1]);
}